// HybridMontecarlo interface
//////////////////////////////////////////////////////////////////////////////


#if !defined(HYBRIDMONTECARLO_H)
#define HYBRIDMONTECARLO_H

# include <iostream>
using namespace std;
# include <cmath>
# include "Function.h"
# include "PhaseSpace.h"

# include "Regulator.h"

# define ALPHA 0.01

//# define END_CONFIGURATION


class HybridMonteCarlo
{
friend ostream &operator<<(ostream &os, HybridMonteCarlo &X);

public : 
    HybridMonteCarlo(int NInput, int NStep, double LStep, Function *Func, double lProp);//, double *mass);
	virtual ~HybridMonteCarlo() 
		{
      //deleteA(m_mass);

#ifdef END_CONFIGURATION
    confFile.close();
#endif

		}

	void 		CreateSamples(double *Input, int NSample, int nMin);
  void    CreateSamplesDiagnosis(double *Input, int NSample, const char filename[], const char filecoord[]);

	void		NewStepNumber(int    N)	{	StepNumber = N;	}
	void		NewStepLength(double x)	{	StepLength = x;	}
	void		SetTemp      (double T)	{	mTemperature	   = T;}

	void		Anneal();
	double	    BestSoFar(double *solution);
  double BestSoFar();

  int nReject;


	// used in main() to test algorithm 

	void ResetTracker(double *I)
	{
		double x;

		x = StoredFunction->Value(I);

		StoredFunction->Result.ResetWith(x,I);
    StoredFunction->Result.ResetCont();
	}


	// for printing out data to frac.cssr
	// (not good programming)
	void GetAcceptAndTotal(int &accept, int &total)
	{
		StepRegulator.GetAcceptAndTotal(accept, total);
	}

	void PrintOpenNewFileForRegulator(char lName[])
	{
		StepRegulator.PrintOpenNewFile(lName);
	}

private :
	int			Metropolis(void);	
	void		HamiltonianPath(void);

  void diagnoseTrajectory(string filename);

	double		StepLength;
	int			StepNumber;
  //double NMin;
  double *m_mass;
	PhaseSpace	InitialConfig, EvolvedConfig;
	Regulator	StepRegulator;


  double mTemperature;
  int numDim;

	Function    *StoredFunction;

#ifdef END_CONFIGURATION
	ofstream    confFile;
#endif 


};


//////////////////////////////////////////////////////////////////////////////
// HybridMontecarlo inline functions
//////////////////////////////////////////////////////////////////////////////

inline void HybridMonteCarlo::Anneal()
	{
//	double AnnealingFactor = 1.0 + ALPHA*mTemperature/(3.0*EnergyVariation);

	double AnnealingFactor = 1.05;

	//mTemperature /= AnnealingFactor;

	//mTemperature -= 5;

//	StepLength /= sqrt(AnnealingFactor);

//	outfile << "Temperature = " << Temp << endl;
	}

#endif // !defined(HYBRIDMONTECARLO_H)
